using NFreeMarker.Template;

namespace NFreeMarker.Core
{
    /**
     * An instruction to visit the children of a node.
     */

    public sealed class RecurseNode : TemplateElement // NOTE: Was internal
    {
        private readonly Expression _targetNode;
        private readonly Expression _namespaces;

        internal RecurseNode(Expression targetNode, Expression namespaces)
        {
            _targetNode = targetNode;
            _namespaces = namespaces;
        }

        internal override void Accept(Environment env)
        {
            ITemplateModel node = _targetNode == null ? null : _targetNode.GetAsTemplateModel(env);
            ITemplateModel nss = _namespaces == null ? null : _namespaces.GetAsTemplateModel(env);
            if (_namespaces is StringLiteral)
            {
                nss = env.ImportLib(((ITemplateScalarModel) nss).GetAsString(), null);
            }
            else if (_namespaces is ListLiteral)
            {
                nss = ((ListLiteral) _namespaces).EvaluateStringsToNamespaces(env);
            }
            if (node != null && !(node is ITemplateNodeModel))
            {
                throw new TemplateException(
                    "Expecting an XML node here, for expression: " + _targetNode + ", found a: " +
                    node.GetType().FullName, env);
            }
            if (nss != null)
            {
                if (nss is ITemplateHashModel)
                {
                    var ss = new SimpleSequence(1);
                    ss.Add(nss);
                    nss = ss;
                }
                else if (!(nss is ITemplateSequenceModel))
                {
                    throw new TemplateException("Expecting a sequence of namespaces after 'using'", env);
                }
            }

            env.Recurse((ITemplateNodeModel) node, (ITemplateSequenceModel) nss);
        }

        public override string GetCanonicalForm()
        {
            string result = "<#recurse";
            if (_targetNode != null) result += (" " + _targetNode.GetCanonicalForm());
            if (_namespaces != null) result += (" using " + _namespaces.GetCanonicalForm());
            return result + "/>";
        }

        public override string GetDescription()
        {
            return "recurse instruction";
        }
    }
}